﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using HalconDotNet;
using CommonLib;
using ElementLib.Interface;
using System.Windows;
using System.Windows.Forms;

namespace ElementLib
{
    public class CC : IComplexMes
    {
        private int type;
        private string name;

        public int Type { get { return type; } set { type = value; } }
        private List<CirclePack> circlePacks;
        private Output output;
        private double supOffsetRow, supOffsetColumn;
        public delegate void drawFunc(string type);
        public static int[] existCount = new int[6];
        private List<string> nameList;


        private SupportLine supportLine;

        public List<CirclePack> CirclePacks
        {
            get { return circlePacks; }
            set { circlePacks = value; }
        }
        public SupportLine SupportLine
        {
            get { return supportLine; }
            set {
                if (value == null) return;
                if (supportLine != null) supportLine.Dispose();
                supportLine = new SupportLine(value); }
        }

      

        public List<string> NameList
        {
            get { return nameList; }
            set
            {

                foreach (var item in value)
                {
                    nameList.Add(item);
                }
            }
        }
        public CC()
        {
            nameList = new List<string>();
            circlePacks = new List<CirclePack>();
        }
        public CC(CC cc)
        {
            supOffsetRow = cc.supOffsetRow;
            supOffsetColumn = cc.supOffsetColumn;
            name = cc.name;
            nameList = new List<string>();
            foreach (var item in cc.nameList)
            {
                nameList.Add(item);
            }
            type = cc.type;
            output = new Output(cc.output);
            circlePacks = new List<CirclePack>();
            foreach (var item in cc.circlePacks)
            {
                circlePacks.Add(new CirclePack(item));
            }
        }
       
        public Output Rs
        {
            get { return output; }
            set { output = value; }
        }

        public void Dispose()
        {
            foreach (var item in circlePacks)
            {
                item.Dispose();
                circlePacks.Clear();
            }
            
        }

        public void CompleteChildElem()
        {

        }
        public void Unload()
        {
            for (int i = 0; i < circlePacks.Count; i++)
            {
                circlePacks[i].Unload();
            }
        }
        public bool loadElem(List<IElemPack> ieps)
        {
            circlePacks = new List<CirclePack>();
            if (ieps.Count > 2)
            {
                MessageBox.Show("只能选择两个圆");
                return false ;
            }
            for (int i = 0; i < ieps.Count; i++)
            {
                string name = ieps[i].GetType().FullName;
                if(name != ConstValue.TYPE_CIRCLEPACK)
                {
                    MessageBox.Show("混有其他基本元素");
                    return false;
                }
                circlePacks.Add(new CirclePack((CirclePack)ieps[i]));
            }
            ieps.Clear();
            return true;
        }

        public void Execute(HObject image, HTuple homMat2D, AddToList add, FindMethod find,AddSupline addSupline)
        {
            HTuple row, column, radius, minDist, maxDist;
            List<Point> tempPoints = new List<Point>();
            HObject rsCircleContour = null;

            for (int i = 0; i < circlePacks.Count; i++)
            {
                if (circlePacks[i].IsDetectType())
                {

                    var circlePtr = find(circlePacks[i].Name, ConstValue.CIRCLE);
                    if (circlePtr != null)
                    {
                        //var ptr = (PointPack)pointPtr;
                        circlePacks[i] = (CirclePack)circlePtr;
                        //add(pointPacks[i], ConstValue.POINT);
                    }
                    else
                    {
                        var circle = circlePacks[i].Detect(image, homMat2D);
                        if (circle == null) { MessageBox.Show("没有检测到"); throw new Exception(); }
                        else
                        {
                            circlePacks[i].C = new Circle((Circle)circle);
                            add(circlePacks[i], ConstValue.CIRCLE);
                        }
                       
                    }
                }
                else
                {
                    var circlePtr = find(circlePacks[i].Name, ConstValue.CIRCLE);
                    if (circlePtr == null)
                    {
                        MessageBox.Show("没有检测到"); throw new Exception();
                    }
                    else
                    {
                        circlePacks[i].C = new Circle((Circle)circlePtr);
                        add(circlePacks[i], ConstValue.CIRCLE);
                    }
                }

            }
            if (circlePacks.Count == 0) throw new Exception();

            switch (type)
            {
                case ConstValue.MEASURE_CC_Cross:

                    GeoMethod.CC_Cross(circlePacks[0].Contours(), circlePacks[1].Contours(), out row, out column);
                    if (circlePacks.Count < 2) throw new Exception();
                    for (int i = 0; i < row.TupleLength(); i++)
                    {
                        tempPoints.Add(new Point(row[i], column[i]));
                    }
                    output = new Output(tempPoints, ConstValue.POINT);
                    break;
                case ConstValue.MEASURE_CC_DIST:
                    if (circlePacks.Count < 2) throw new Exception();
                    HOperatorSet.DistanceCc(circlePacks[0].Contours(), circlePacks[1].Contours(), "point_to_point", out minDist, out maxDist);
                    double[] rs1 = { (double)minDist, (double)maxDist };
                    output = new Output(rs1, ConstValue.DISTANCE);
                    break;
                case ConstValue.MEASURE_CC_Mid:
                    if (circlePacks.Count < 2) throw new Exception();
                    HObject midCircleContour;
                    GeoMethod.CC_Mid(circlePacks[0].Contours(), circlePacks[1].Contours(), out midCircleContour, out row, out column, out radius);
                    output = new Output(new Circle(new Point(row, column), radius, midCircleContour), ConstValue.LINE);
                    break;
                case ConstValue.MEASURE_C_RADIUS:
                    if (circlePacks.Count == 0) throw new Exception();
                    int[] dists = new int[circlePacks.Count];
                    for (int i = 0; i < circlePacks.Count; i++)
                    {

                    }
                    foreach (var circlePack in circlePacks)
                    {
                        GeoMethod.C_Center(circlePack.Contours(), out row, out column);
                        tempPoints.Add(new Point(row, column));
                    }
                    output = new Output(tempPoints, ConstValue.DISTANCE);
                    break;
                case ConstValue.MEASURE_C_Center:
                    if (circlePacks.Count == 0) throw new Exception();
                    foreach (var circlePack in circlePacks)
                    {
                        GeoMethod.C_Center(circlePack.Contours(), out row, out column);
                        tempPoints.Add(new Point(row, column, "圆心" + existCount[3]));
                    }
                    output = new Output(tempPoints, ConstValue.POINT);
                    break;
                case ConstValue.MEASURE_Arc_Concat:
                    if (circlePacks.Count < 2) throw new Exception();
                    HObject arcTuple = new HObject();
                    foreach (var arc in circlePacks)
                    {
                        arcTuple = arcTuple.ConcatObj(arc.Contours());
                    }
                    GeoMethod.Arc_Concat(arcTuple, out rsCircleContour, out row, out column, out radius);
                    output = new Output(new Circle(new Point(row, column), radius, rsCircleContour), ConstValue.CIRCLE);
                    break;
                case ConstValue.MEASURE_ARC_ANGLE:
                    if (circlePacks.Count == 0) throw new Exception();
                    double[] temp = new double[circlePacks.Count];
                    HTuple angle, angleTuple = new HTuple();
                    for (int i = 0; i < circlePacks.Count; i++)
                    {
                        GeoMethod.Arc_Angle(circlePacks[i].Contours(), out angle);
                        temp[i] = (double)angle;
                    }
                    output = new Output(temp, ConstValue.DISTANCE);
                    break;
                default:
                    break;
            }
        }
        public void ApplyChange(string mode)
        {

            switch (type)
            {
                case ConstValue.MEASURE_CC_Cross:
                    if (mode == "add") name = "圆相交点" + existCount[0]++;
                    break;
                case ConstValue.MEASURE_CC_DIST:
                    supOffsetRow = supportLine.RowOffset;
                    supOffsetColumn = supportLine.ColumnOffset;
                    if (mode == "add") name = "圆间距离" + existCount[1]++;
                    break;
                case ConstValue.MEASURE_CC_Mid:
                    if (mode == "add") name = "圆圆中间圆" + existCount[2]++;
                    break;
                case ConstValue.MEASURE_C_Center:
                    if (mode == "add") name = "圆心" + existCount[3]++;
                    break;
                case ConstValue.MEASURE_Arc_Concat:
                    if (mode == "add") name = "圆弧拼接" + existCount[4]++;
                    break;
                case ConstValue.MEASURE_ARC_ANGLE:
                    if (mode == "add") name = "圆弧角度" + existCount[5]++;
                    break;
            }
       
        }

        public string Name { get { return name; } set { name = value; } }
        /// <summary>
        /// 规划阶段使用这个执行
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        public Output Execute(FindMethod method)
        {
          
            HTuple row, column, radius, minDist, maxDist;
            List<Point> tempPoints = new List<Point>();
            HObject rsCircleContour = null;

            if (nameList != null)
            {
                foreach (var name in nameList)
                {
                    Circle circle =(Circle)method(name, ConstValue.CIRCLE);
                    if(circle == null)
                    {
                        throw new Exception();
                    }
                    circlePacks.Add(new CirclePack() { C = new Circle(circle) });
                }
            }
            if (circlePacks.Count == 0) return  null;




            switch (type)
            {
                case ConstValue.MEASURE_CC_Cross:
                    
                    GeoMethod.CC_Cross(circlePacks[0].Contours(), circlePacks[1].Contours(), out row, out column);
                    if (circlePacks.Count < 2) throw new Exception();
                    for (int i = 0; i < row.TupleLength(); i++)
                    {
                        tempPoints.Add(new Point(row[i], column[i]));
                    }
                    output = new Output(tempPoints, ConstValue.POINT);
                    break;
                case ConstValue.MEASURE_CC_DIST:
                    if (circlePacks.Count < 2) throw new Exception();
                    HOperatorSet.DistanceCc(circlePacks[0].Contours(), circlePacks[1].Contours(), "point_to_point", out minDist, out maxDist);
                    double[] rs1 = { (double)minDist, (double)maxDist };
                    output = new Output(rs1, ConstValue.DISTANCE);
                    break;
                case ConstValue.MEASURE_CC_Mid:
                    if (circlePacks.Count < 2) throw new Exception();
                    HObject midCircleContour;
                    GeoMethod.CC_Mid(circlePacks[0].Contours(), circlePacks[1].Contours(), out midCircleContour, out row, out column, out radius);
                    output = new Output(new Circle(new Point(row, column), radius, midCircleContour), ConstValue.LINE);
                    break;
                case ConstValue.MEASURE_C_RADIUS:
                    if (circlePacks.Count == 0) throw new Exception();
                    int[] dists = new int[circlePacks.Count];
                    for (int i = 0; i < circlePacks.Count; i++)
                    {

                    }
                    foreach (var circlePack in circlePacks)
                    {
                        GeoMethod.C_Center(circlePack.Contours(), out row, out column);
                        tempPoints.Add(new Point(row, column));
                    }
                    output = new Output(tempPoints, ConstValue.DISTANCE);
                    break;
                case ConstValue.MEASURE_C_Center:
                   
                    if (circlePacks.Count == 0) throw new Exception();
                    foreach (var circlePack in circlePacks)
                    {
                        GeoMethod.C_Center(circlePack.Contours(), out row, out column);
                        tempPoints.Add(new Point(row, column, "圆心" + existCount[3]));
                    }
                    output = new Output(tempPoints, ConstValue.POINT);
                    break;
                case ConstValue.MEASURE_Arc_Concat:
                    if (circlePacks.Count < 2) throw new Exception();
                    HObject arcTuple = new HObject();
                    foreach (var arc in circlePacks)
                    {
                        arcTuple = arcTuple.ConcatObj(arc.Contours());
                    }
                    GeoMethod.Arc_Concat(arcTuple, out rsCircleContour, out row, out column, out radius);
                    output = new Output(new Circle(new Point(row, column), radius, rsCircleContour), ConstValue.CIRCLE);
                    break;
                case ConstValue.MEASURE_ARC_ANGLE:
                    if (circlePacks.Count == 0) throw new Exception();
                    double[] temp = new double[circlePacks.Count];
                    HTuple angle,angleTuple = new HTuple();
                    for (int i = 0; i < circlePacks.Count; i++)
                    {
                        GeoMethod.Arc_Angle(circlePacks[i].Contours(), out angle);
                        temp[i] = (double)angle;
                    }
                    output = new Output(temp, ConstValue.DISTANCE);
                    break;
                default:
                    break;
            }
 
            return output;
            
        }

        /// <summary>
        /// 实际测量阶段使用这个执行
        /// </summary>
        /// <param name="image"></param>
        /// <param name="homMat2D"></param>
        /// <param name="reverseHomMat2D"></param>
        /// <param name="add"></param>
        /// <param name="find"></param>
        /// <param name="addSupline"></param>
        public void Execute(HObject image, HTuple homMat2D, HTuple reverseHomMat2D, AddToList add, FindMethod find, AddSupline addSupline)
        {
            for (int i = 0; i < circlePacks.Count; i++)
            {
                if (circlePacks[i].IsDetectType())
                {
                    var circlePtr = find(circlePacks[i].Name, ConstValue.CIRCLE);
                    if (circlePtr != null)
                    {
                        //var ptr = (PointPack)pointPtr;
                        circlePacks[i] = (CirclePack)circlePtr;
                        //add(pointPacks[i], ConstValue.POINT);
                    }
                    else
                    {
                        var circle = circlePacks[i].Detect(image, homMat2D);
                        if (circle == null) { MessageBox.Show("没有检测到"); throw new Exception(); }
                        else
                        {
                            circlePacks[i].C = new Circle((Circle)circle);
                            add(circlePacks[i], ConstValue.CIRCLE);
                        }
                    }

                }
                else
                {
                    var circlePtr = find(circlePacks[i].Name, ConstValue.CIRCLE);
                    if (circlePtr == null)
                    {
                        MessageBox.Show("没有检测到"); throw new Exception();
                    }
                    else
                    {
                        circlePacks[i].C = new Circle((Circle)circlePtr);
                        add(circlePacks[i], ConstValue.CIRCLE);
                    }
                }
            }


            Output output = null;
            HTuple row, column, minDist, maxDist, radius = null;
            Circle rsCircle = null;
            List<Point> tempPoints = new List<Point>();
            switch (type)
            {

                case ConstValue.MEASURE_CC_Cross:

                    GeoMethod.CC_Cross(circlePacks[0].Contours(), circlePacks[1].Contours(), out row, out column);
                    if (circlePacks.Count < 2) throw new Exception();
                    for (int i = 0; i < row.TupleLength(); i++)
                    {
                        Point p = new Point(row[i], column[i]);
                        add(new PointPack() { P=p,Name=p.Name}, ConstValue.POINT);
                        tempPoints.Add(p);
                    }
                    //output = new Output(tempPoints, ConstValue.POINT);
                    break;
                case ConstValue.MEASURE_CC_DIST:
                    if (circlePacks.Count < 2) throw new Exception();
                    HOperatorSet.DistanceCc(circlePacks[0].Contours(), circlePacks[1].Contours(), "point_to_point", out minDist, out maxDist);
                    double[] rs1 = { (double)minDist, (double)maxDist };
                    //output = new Output(rs1, ConstValue.DISTANCE);
                    break;
                case ConstValue.MEASURE_CC_Mid:
                    if (circlePacks.Count < 2) throw new Exception();
                    HObject midCircleContour;
                    GeoMethod.CC_Mid(circlePacks[0].Contours(), circlePacks[1].Contours(), out midCircleContour, out row, out column, out radius);
                    rsCircle = new Circle(new Point(row, column), radius, midCircleContour);
                    add(new CirclePack() { C = rsCircle, Name = rsCircle.Name }, ConstValue.CIRCLE);
                    //output = new Output(rsCircle, ConstValue.CIRCLE);
                    break;
                case ConstValue.MEASURE_C_RADIUS:
                    if (circlePacks.Count == 0) throw new Exception();
                    int[] dists = new int[circlePacks.Count];
                    for (int i = 0; i < circlePacks.Count; i++)
                    {

                    }
                    foreach (var circlePack in circlePacks)
                    {
                        GeoMethod.C_Center(circlePack.Contours(), out row, out column);
                        tempPoints.Add(new Point(row, column));
                    }
                    output = new Output(tempPoints, ConstValue.DISTANCE);
                    break;
                case ConstValue.MEASURE_C_Center:
                    if (circlePacks.Count == 0) throw new Exception();
                    foreach (var circlePack in circlePacks)
                    {
                        GeoMethod.C_Center(circlePack.Contours(), out row, out column);
                        var p = new Point(row, column);
                        PointPack pointPack = new PointPack() { P = new Point(p),Name = name};
                        if(find(p.Name,ConstValue.POINT)==null||p.Name == null)add(pointPack, ConstValue.POINT);
                        tempPoints.Add(p);
                    }
                    output = new Output(tempPoints, ConstValue.POINT);
                    break;
                case ConstValue.MEASURE_Arc_Concat:
                    HObject rsCircleContour=null;
                    if (circlePacks.Count < 2) throw new Exception();
                    HObject arcTuple = new HObject();
                    foreach (var arc in circlePacks)
                    {
                        arcTuple = arcTuple.ConcatObj(arc.Contours());
                    }
                    GeoMethod.Arc_Concat(arcTuple, out rsCircleContour, out row, out column, out radius);
                    rsCircle = new Circle(new Point(row, column), radius, rsCircleContour);
                    add(new CirclePack() { C= rsCircle ,Name=rsCircle.Name}, ConstValue.CIRCLE);
                    //output = new Output(rsCircle, ConstValue.CIRCLE);
                    break;
                case ConstValue.MEASURE_ARC_ANGLE:
                    if (circlePacks.Count == 0) throw new Exception();
                    double[] temp = new double[circlePacks.Count];
                    HTuple angle, angleTuple = new HTuple();
                    for (int i = 0; i < circlePacks.Count; i++)
                    {
                        GeoMethod.Arc_Angle(circlePacks[i].Contours(), out angle);
                        temp[i] = (double)angle;
                    }
                    //output = new Output(temp, ConstValue.DISTANCE);
                    break;
                default:
                    break;
            }

        }


    }
}
